//------------------------------------------------------------
//  Filename: vga_lvds_driver.v
//   
//  Author  : wlduan@gmail.com
//  Revise  : 2017-09-14 11:37
//  Description: 
//   
//  Copyright (C) 2014, YRBD, Inc. 					      
//  All Rights Reserved.                                       
//-------------------------------------------------------------
//
`timescale 1ns/1ps
 
module VGA_LVDS_DRIVER ( 
	 input  wire       clk_7x_vga,
    output wire       clk_vga_out,	
	 input wire        rst,
    input  wire [7:0] vga_R, 
    input  wire [7:0] vga_G, 
    input  wire [7:0] vga_B, 

    input  wire       vga_h_sync,
    input  wire       vga_v_sync,
    input  wire       vga_de,

    output wire       txout0_p,
    output wire       txout0_n,

    output wire       txout1_p,
    output wire       txout1_n,

    output wire       txout2_p,
    output wire       txout2_n,

    output wire       txout3_p,
    output wire       txout3_n,

    output wire       txclk_p,
    output wire       txclk_n
); 
//--------------------------------------------------------
wire clk = clk_7x_vga;
//--------------------------------------------------------
reg  txout0;
reg  txout1;
reg  txout2;
reg  txout3;
reg  txclk;
//--------------------------------------------------------
reg[3:0] shift_out_cntr;
//--------------------------------------------------------
always @(posedge clk,posedge rst) begin
    if(rst)begin 
        shift_out_cntr <= 4'h0;    
    end 
    else if(shift_out_cntr < 6)begin 
        shift_out_cntr <= shift_out_cntr + 1;    
    end 
    else begin
        shift_out_cntr <= 4'h0;    
    end
end 
//--------------------------------------------------------
wire[31:0] s_axis_tdata = {5'b0,vga_de,vga_v_sync,vga_h_sync,vga_B,vga_G,vga_R};
wire       s_axis_tready;
wire       m_axis_tvalid;
wire       m_axis_tready = (shift_out_cntr == 0)?1'b1:1'b0;
wire[31:0] m_axis_tdata ;
//--------------------------------------------------------
fifo_generator_vga fifo_inst0  (
    .s_aclk        ( clk_vga_out   ) ,
    .s_aresetn     ( ~rst          ) ,
    .s_axis_tdata  ( s_axis_tdata  ) ,
    .s_axis_tvalid ( s_axis_tready ) ,
    .s_axis_tready ( s_axis_tready ) ,

    .m_aclk        ( clk_7x_vga    ) ,
    .m_axis_tvalid ( m_axis_tvalid ) ,
    .m_axis_tready ( m_axis_tready ) ,
    .m_axis_tdata  ( m_axis_tdata  )
);
//--------------------------------------------------------
reg[7:0] pr ; 
reg[7:0] pg ; 
reg[7:0] pb ; 
reg      hs ; 
reg      vs ; 
reg      de ; 
//--------------------------------------------------------
always @(posedge clk,posedge rst) begin
    if(rst)begin 
        pr <= 8'b0;
        pg <= 8'b0;
        pb <= 8'b0;
        hs <= 1'b0;
        vs <= 1'b0;
        de <= 1'b0;
    end 
    else if(m_axis_tready) begin 
        pr <= m_axis_tdata[7:0];
        pg <= m_axis_tdata[15:8];
        pb <= m_axis_tdata[23:16];
        hs <= m_axis_tdata[24];
        vs <= m_axis_tdata[25];
        de <= m_axis_tdata[26];
    end 
end 
//--------------------------------------------------------
reg[6:0] shift_data0;
reg[6:0] shift_data1;
reg[6:0] shift_data2;
reg[6:0] shift_data3;
//--------------------------------------------------------
wire[27:0] txIN = {{pr[6],de,vs,hs,1'b0,pb[5:4]},
                   {pb[3:1],pb[7:6],pb[0],pg[5]},
                   {pg[4:3],pg[7:6],pg[2:0]},
                   {pr[5],pr[7],pr[4:0]}};
//--------------------------------------------------------
always @(posedge clk,posedge rst) begin
    if(rst)begin 
        shift_data0 <= 7'h0;    
        shift_data1 <= 7'h0;    
        shift_data2 <= 7'h0;    
        shift_data3 <= 7'h0;    
    end 
    else if (shift_out_cntr == 0) begin 
        shift_data0 <= {txIN[7:6],txIN[4:0]};
        shift_data1 <= {txIN[18],txIN[15:12],txIN[9:8]};
        shift_data2 <= {txIN[26:24],txIN[22:19]};
        shift_data3 <= {txIN[23],txIN[17:16],txIN[11:10],txIN[5],txIN[27]};        
    end 
    else begin
        shift_data0 <= {shift_data0[5:0],1'b0};
        shift_data1 <= {shift_data1[5:0],1'b0};
        shift_data2 <= {shift_data2[5:0],1'b0};
        shift_data3 <= {shift_data3[5:0],1'b0};
    end
end 
//--------------------------------------------------------
reg phase_clk;
//--------------------------------------------------------
always @(posedge clk,posedge rst) begin
    if(rst)begin 
        phase_clk <= 1'b0;    
    end 
    else if((shift_out_cntr == 2)||(shift_out_cntr == 3)||(shift_out_cntr == 4)) begin 
        phase_clk <= 1'b0;    
    end 
    else begin
        phase_clk <= 1'b1;    
    end
end 
//--------------------------------------------------------
always @(posedge clk,posedge rst) begin
    if(rst)begin 
        txout0 <= 1'b0;
        txout1 <= 1'b0;
        txout2 <= 1'b0;
        txout3 <= 1'b0;  
        txclk  <= 1'b0;        
    end 
    else begin 
        txout0 <= shift_data0[6];
        txout1 <= shift_data1[6];
        txout2 <= shift_data2[6];
        txout3 <= shift_data3[6];               
        txclk  <= phase_clk;        
    end 
end 
//--------------------------------------------------------
OBUFDS OBUFDS_inst0(
    .I  ( txout0   ),
    .O  ( txout0_p ),
    .OB ( txout0_n )
);
//--------------------------------------------------------
OBUFDS OBUFDS_inst1(
    .I  ( txout1   ),
    .O  ( txout1_p ),
    .OB ( txout1_n )
);
//--------------------------------------------------------
OBUFDS OBUFDS_inst2(
    .I  ( txout2   ),
    .O  ( txout2_p ),
    .OB ( txout2_n )
);
//--------------------------------------------------------
OBUFDS OBUFDS_inst3(
    .I  ( txout3   ),
    .O  ( txout3_p ),
    .OB ( txout3_n )
);

//--------------------------------------------------------
OBUFDS OBUFDS_inst4(
    .I  ( txclk   ),
    .O  ( txclk_p ),
    .OB ( txclk_n )
);

BUFG BUFG_inst0(
    .I( phase_clk   ),
    .O( clk_vga_out )
);

//assign txclk_p = txclk;

endmodule

